﻿using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Net;
using System.Collections.Generic;

using Nuclex.Game.States;
using Nuclex.UserInterface;

namespace WarPigs
{
    class InGameGameState : DrawableGameState
    {
        //Graphics Devices
        GraphicsDeviceManager graphics;
        GraphicsDevice device;

        //Stores the picked X and Y coordinate
        private Vector2 hilite_tile;

        //Shader Variables
        public BasicEffect basicEffect;
        public Effect MapEffect;
        
        //Declares a new hex object and size.
        Hex hex = new Hex(1.0f);

        //Holds vertexes for drawing the hexes
        private List<Vector2> data =
            new List<Vector2>();
        VertexPositionColor[] hex_vert = new VertexPositionColor[18];
        //VertexPositionColorTexture[] hex_vert = new VertexPositionColorTexture[18];
        private VertexDeclaration vertexDeclaration;

        System.Int16[] hex_index = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 6, 7, 9, 9, 8, 6, 8, 9, 11, 11, 10, 8, 10, 11, 13, 13, 12, 10, 12, 13, 15, 15, 14, 12, 14, 15, 17, 17, 16, 14, 16, 17, 7, 7, 6, 16 };

        //GUI Variables
        //Screen gameScreen;
        //GuiManager guiManager;
        TileDataDialog tileDataDialog; //Lower left - displays info about currently picked tile
        private SpriteBatch spriteBatch;
        private SpriteFont arial24sprite;

        //Map Management
        public Map newMap; //Map object variable
        
        //Drawing Variables
        int tileID = 0; //Terrain type
        int ownerID = 10; //Ownership
        int resourceID = 0; //Resources
        int fogID = 0;

        //Faction Management
        FactionManager factionManager;

        //Player Management
        PlayerManager playerManager;

        //Turn management
        //Turnmanager turnManager;

        //Camera Management
        Camera camera;

        //Screenshot Management
        Screenshot screenshot;

        //Game Management
        WarPigs game;

        //Savegame Management
        LocalPlayerData localPlayerData;

        //Terrain Textures
        //Texture2D grassTexture;
        //Texture2D mountainTexture;
        //Texture2D lakeTexture;
        //Texture2D marshTexture;
        //Texture2D jungleTexture;
        //Texture2D forestTexture;
        //Texture2D desertTexture;
        //Texture2D oceanTexture;

        //Resource Icons
        //Texture2D resourceOil;
        //Texture2D resourceWood;
        //Texture2D resourceWind;
        //Texture2D resourceWater;
        //Texture2D resourceStone;

        //In-Game UI
        GuiManager guiManager;
        Screen gameScreen;


        /// <summary>
        /// Constructs the indices for the hexagon design
        /// </summary>
        /// Color-based
        void BuildHexMesh()
        {
            Vector3 exterior = new Vector3(0.0f, 1.0f, 0.0f);
            Vector3 interior = new Vector3(0.0f, 0.9f, 0.1f);
            Matrix poly_rot = Matrix.CreateRotationZ(MathHelper.ToRadians(-60));

            for (int i = 0; i < 6; ++i)
            {
                hex_vert[i] = new VertexPositionColor(interior, Color.White);
                hex_vert[(i * 2) + 6] = new VertexPositionColor(interior, Color.Gray);
                hex_vert[(i * 2) + 7] = new VertexPositionColor(exterior, Color.Black);

                exterior = Vector3.Transform(exterior, poly_rot);
                interior = Vector3.Transform(interior, poly_rot);
            }
        }

        //Texture-based
        //void BuildHexMesh()
        //{
        //    Vector3 exterior = new Vector3(0.0f, 1.0f, 0.0f);
        //    Vector3 interior = new Vector3(0.0f, 0.9f, 0.1f);
        //    Matrix poly_rot = Matrix.CreateRotationZ(MathHelper.ToRadians(-60));

        //    for (int i = 0; i < 6; ++i)
        //    {
        //        hex_vert[i] = new VertexPositionColorTexture();
        //        hex_vert[(i * 2) + 6] = new VertexPositionColorTexture();
        //        hex_vert[(i * 2) + 7] = new VertexPositionColorTexture();

        //        exterior = Vector3.Transform(exterior, poly_rot);
        //        interior = Vector3.Transform(interior, poly_rot);
        //    }
        //}

        /// <summary>
        /// Creates the Base UI for the in game.
        /// </summary>
        /// <param name="mainScreen"></param>
        private void createBaseUI(Screen mainScreen)
        {
            tileDataDialog = new TileDataDialog();
            //gameScreen.Desktop.Children.Add(tileDataDialog);            
        }

        public string text = " ";






        public InGameGameState(GraphicsDeviceManager passedGraphics, GraphicsDevice passedDevice, ContentManager passedContent, SpriteBatch passedBatch, GuiManager passedGui, WarPigs passedGame)
        {
            //Passed from constructor
            graphics = passedGraphics;
            device = passedDevice;
            spriteBatch = passedBatch;
            guiManager = passedGui;
            game = passedGame;
            localPlayerData = game.localPlayerData;

            //Font loader for drawing debugging text
            arial24sprite = passedContent.Load<SpriteFont>(@"ArialFont");

            //Shader
            MapEffect = passedContent.Load<Effect>(@"MapEffect");
            


            //makes the in game HUD...when I write one.
            Viewport viewport = device.Viewport;
            gameScreen = new Screen(viewport.Width, viewport.Height);
            guiManager.Screen = gameScreen;

            gameScreen.Desktop.Bounds = new UniRectangle(
              new UniScalar(0.1f, 0.0f), new UniScalar(0.1f, 0.0f), // x and y
              new UniScalar(0.8f, 0.0f), new UniScalar(0.8f, 0.0f) // width and height
            );

            //createBaseUI(gameScreen); 

            //Initialize Textures
            //oceanTexture = passedContent.Load<Texture2D>(@"Textures\Ocean");
            //grassTexture = passedContent.Load<Texture2D>(@"Textures\Grass");
            //mountainTexture = passedContent.Load<Texture2D>(@"Textures\Mountain");
            //lakeTexture = passedContent.Load<Texture2D>(@"Textures\Lake");
            //marshTexture = passedContent.Load<Texture2D>(@"Textures\Marsh");
            //jungleTexture = passedContent.Load<Texture2D>(@"Textures\Jungle");
            //forestTexture = passedContent.Load<Texture2D>(@"Textures\Forest");
            //desertTexture = passedContent.Load<Texture2D>(@"Textures\Desert");

            //resourceOil = passedContent.Load<Texture2D>(@"Textures\Resources\oilTile");
            //resourceWood = passedContent.Load<Texture2D>(@"Textures\Resources\woodTile");
            //resourceWind = passedContent.Load<Texture2D>(@"Textures\Resources\windTile");
            //resourceWater = passedContent.Load<Texture2D>(@"Textures\Resources\waterTile");
            //resourceStone = passedContent.Load<Texture2D>(@"Textures\Resources\stoneTile");


            
        }

        protected override void OnEntered()
        {


            //Construct hex shape tiles and default picking location
            BuildHexMesh();
            hilite_tile = hex.TileAt(new Vector2(0, 0));


            //Initialize map arrays
            newMap = new Map("small", "temperate", 1, "common");
            newMap.Create();

            //Initialize Faction arrays
            factionManager = new FactionManager(newMap);
            factionManager.createFactions();
            factionManager.placeFactions();

            //Initialize Player arrays
            playerManager = new PlayerManager(5, newMap, localPlayerData, game);


            //Counts the map's size
            for (int X = 0; X < newMap.tiles.X; ++X)
                for (int Y = 0; Y < newMap.tiles.Y; ++Y)
                    data.Add(new Vector2(X, Y));

            //MapEffect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 16.0f / 10.0f, 0.1f, 100.0f); Hmm...
            basicEffect = new BasicEffect(device);
            basicEffect.VertexColorEnabled = true;
            //basicEffect.TextureEnabled = true;
            basicEffect.Projection =
                Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 16.0f / 10.0f, 0.1f, 100.0f);
            //basicEffect.LightingEnabled = true;

            //vertexDeclaration = new VertexDeclaration(VertexPositionTexture.VertexDeclaration.GetVertexElements());
            
            //Initialize Camera
            camera = new Camera(72.0f, 0.0f, 0.0f, 25.0f); //(72.0f, 52.0f, 0.0f, 25.0f);
            Vector2 startTile = hex.TileCenter(new Vector2(playerManager.players[0].hqCoordinates.X, playerManager.players[0].hqCoordinates.Y));
            camera.Focus.X = startTile.X;
            camera.Focus.Y = startTile.Y;
            //Initialize Screenshots
            //screenshot = new Screenshot();
            base.OnEntered();
        }

        protected override void OnLeaving()
        {
            base.OnLeaving();
        }

        protected override void OnPause()
        {
            base.OnPause();
        }

        protected override void OnResume()
        {
            base.OnResume();
        }
   
        public override void Update(GameTime gameTime)
        {
            //360 Gamepad Controls
            GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);
            camera.Orbit(gamepadState.ThumbSticks.Right.X * 4.0f);
            camera.Pitch(gamepadState.ThumbSticks.Right.Y * 4.0f);
            camera.Pan(gamepadState.ThumbSticks.Left.X, gamepadState.ThumbSticks.Left.Y, 0.25f);
            
            //Tile picker
            hilite_tile = hex.TileAt(new Vector2(camera.Focus.X, camera.Focus.Y));
            
            //text = "Hilight Tile is " + hilite_tile.X.ToString() + " and " + hilite_tile.Y.ToString();
            //if (gamepadState.Buttons.Back == ButtonState.Pressed) Exit();

            //PC Controls
            KeyboardState keyboardState = Keyboard.GetState();
            if (keyboardState.IsKeyDown(Keys.W) && keyboardState.IsKeyDown(Keys.LeftShift))
            {
                camera.Pitch(-0.10f);
            }
            if (keyboardState.IsKeyDown(Keys.S) && keyboardState.IsKeyDown(Keys.LeftShift))
            {
                camera.Pitch(0.10f);
            }            
            if (keyboardState.IsKeyDown(Keys.D) && hilite_tile.X < newMap.tiles.X - 1)
            {
                camera.Pan(1.0f, 0.0f, 0.20f);
            }
            if (keyboardState.IsKeyDown(Keys.A) && hilite_tile.X > 0)
            {
                camera.Pan(-1.0f, 0.0f, 0.20f);
            }
            if (keyboardState.IsKeyDown(Keys.W) && keyboardState.IsKeyUp(Keys.LeftShift) && hilite_tile.Y < newMap.tiles.Y - 1)
            {
                camera.Pan(0.0f, 1.0f, 0.25f);
            }
            if (keyboardState.IsKeyDown(Keys.S) && keyboardState.IsKeyUp(Keys.LeftShift) && hilite_tile.Y > 0)
            {
                camera.Pan(0.0f, -1.0f, 0.25f);
            }
            if (keyboardState.IsKeyDown(Keys.F12))
            {
                //screenshot.TakeScreenshot(device);
            }
        }

        public override void Draw(GameTime gameTime)
        {
            basicEffect.View = camera.ViewMatrix;
            device.Clear(Color.Black);



            text = " ";

            //Colors each tile appropriately
            //This logic needs to add in only displaying things like fog of war to the active player.
            foreach (Vector2 item in data)
            {
                basicEffect.World = Matrix.CreateTranslation(new Vector3(hex.TileCenter(item), 0.0f));

                //Loads up the ownership and terrain arrays for coloring
                if (item.X <= newMap.tiles.X && item.Y <= newMap.tiles.Y)
                {
                    tileID = newMap.terrainarray[(int)item.X, (int)item.Y];
                    ownerID = newMap.ownershiparray[(int)item.X, (int)item.Y];
                    resourceID = newMap.resourcearray[(int)item.X, (int)item.Y];
                    fogID = newMap.fogofwar[(int)item.X, (int)item.Y];
                }

                ////Terrain Textured
                //switch (tileID.ToString())
                //{
                //    case "0": basicEffect.Texture = oceanTexture; break;
                //    case "1": basicEffect.Texture = grassTexture; break;
                //    case "2": basicEffect.Texture = mountainTexture; break;
                //    case "3": basicEffect.Texture = lakeTexture; break;
                //    case "4": basicEffect.Texture = marshTexture; break;
                //    case "5": basicEffect.Texture = jungleTexture; break;
                //    case "6": basicEffect.Texture = forestTexture; break;
                //    case "7": basicEffect.Texture = desertTexture; break;
                //    default: basicEffect.DiffuseColor = Color.Red.ToVector3(); break;
                //}

                //Terrain Colors
                switch (tileID.ToString())
                {
                    case "0": basicEffect.DiffuseColor = Color.DarkBlue.ToVector3(); break;
                    case "1": basicEffect.DiffuseColor = Color.Green.ToVector3(); break;
                    case "2": basicEffect.DiffuseColor = Color.DarkSlateGray.ToVector3(); break;
                    case "3": basicEffect.DiffuseColor = Color.LightBlue.ToVector3(); break;
                    case "4": basicEffect.DiffuseColor = Color.DarkSeaGreen.ToVector3(); break;
                    case "5": basicEffect.DiffuseColor = Color.LimeGreen.ToVector3(); break;
                    case "6": basicEffect.DiffuseColor = Color.DarkGreen.ToVector3(); break;
                    case "7": basicEffect.DiffuseColor = Color.SandyBrown.ToVector3(); break;
                    default: basicEffect.DiffuseColor = Color.Red.ToVector3(); break;
                }

                //Ownership (No nulls allowed) Colors
                if (this.factionManager.plsFaction != null  && this.playerManager != null)
                switch (ownerID.ToString())
                {
                    case "1": basicEffect.DiffuseColor = this.factionManager.plsFaction.color.ToVector3(); break;
                    case "2": basicEffect.DiffuseColor = this.factionManager.colFaction.color.ToVector3(); break;
                    case "3": basicEffect.DiffuseColor = this.factionManager.wesFaction.color.ToVector3(); break;
                    case "4": basicEffect.DiffuseColor = this.factionManager.honFaction.color.ToVector3(); break;
                    case "5": basicEffect.DiffuseColor = this.factionManager.marFaction.color.ToVector3(); break;
                    case "6": basicEffect.DiffuseColor = Color.Beige.ToVector3(); break; //playerManager.players[0].color.ToVector3(); break;

                    

                    case "7": 
                        if(playerManager.players[1] != null)
                            basicEffect.DiffuseColor = playerManager.players[1].color.ToVector3(); break;

                    case "8":
                        if (playerManager.players[2] != null)
                            basicEffect.DiffuseColor = playerManager.players[2].color.ToVector3(); break;

                    case "9":
                        if (playerManager.players[3] != null)
                            basicEffect.DiffuseColor = playerManager.players[3].color.ToVector3(); break;

                    case "10":
                        if (playerManager.players[4] != null)
                            basicEffect.DiffuseColor = playerManager.players[4].color.ToVector3(); break;

                    case "11":
                        if (playerManager.players[5] != null)
                            basicEffect.DiffuseColor = playerManager.players[5].color.ToVector3(); break;
                   
                    default:
                        break;
                }

               
                //Resources
                //At this point we may be at the limits of basic effect.

                switch (fogID)
                {
                    case 0: basicEffect.DiffuseColor = Color.Black.ToVector3(); break; //Unexplored, hide completely.
                    case 1: basicEffect.DiffuseColor = Color.DarkGray.ToVector3(); break; //SHADER REQUIRED - tile needs transparency
                    case 2: break; //Reveal full tile
                    default:
                        break;
                }
                
                //Picking Color
                if (item == hilite_tile)
                {
                    basicEffect.DiffuseColor = Color.Red.ToVector3();
                }

                //And DRAW
                basicEffect.CurrentTechnique.Passes[0].Apply();
                device.DrawUserIndexedPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, hex_vert, 0, hex_vert.Length, hex_index, 0, hex_index.Length / 3);

                //basicEffect.CurrentTechnique.Passes[0].Apply();
                //device.DrawUserIndexedPrimitives<VertexPositionColorTexture>(PrimitiveType.TriangleList, hex_vert, 0, hex_vert.Length, hex_index, 0, hex_index.Length / 3, vertexDeclaration);              
            }


            spriteBatch.Begin();

            if (hilite_tile.X >= 0 && hilite_tile.Y >= 0)
            {
                this.spriteBatch.DrawString(
                this.arial24sprite,
                newMap.ownershiparray[(int)hilite_tile.X, (int)hilite_tile.Y].ToString(),
                new Vector2(60.0f, 60.0f),
                new Color(255, 255, 255, 255)
                );
            }

            spriteBatch.End();
        }
    }
}
